home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************/
- /* inter.c */
- /* */
- /* Ray / Object intersection routines. */
- /* Some routines modified from Optik v(1.2e) (C) 1987 by John */
- /* Amanatides and Andrew Woo. */
- /* */
- /* Copyright (C) 1992, Bernard Kwok */
- /* All rights reserved. */
- /* Revision 1.0 */
- /* May, 1992 */
- /**********************************************************************/
- #include <stdio.h>
- #include "geo.h"
- #include "struct.h"
- #include "misc.h"
- #include "io.h"
- #include "ray.h"
- #include "bvol.h"
- #include "ff.h"
- #include "rtime.h"
-
- /**********************************************************************/
- extern OptionType Option; /* Options */
- extern FF_OptionType FF_Options;
- extern Object_List *objlist;
- extern int objlist_size;
- extern Polygon *shootPatch;
- extern Polygon *recPatch;
- extern Scene RadScene; /* The scene */
- extern HBBox Scene_BVH; /* Hierarchical bounding boxes for scene */
- extern Time_Stats tstats;
- extern FILE *rlogfile;
-
- extern void HitTransform();
- extern void RayTransform();
- extern Plane PlaneTransform();
- extern
- BoundingBoxType BoundingBoxTransform(), BoxCube(), BoxCone(), BoxPoly(),
- BoxSquare(), BoxSphere(), BoxTriangle(), BoxCylinder(),
- BoxDisk();
-
- /**********************************************************************/
- void StartIntersect();
- void EndIntersect();
- int HitObject();
- void RayObject();
- HitData RayIntersect();
- void RayPolyBVH();
- void RayBVH();
-
- RayStats_Type RayStats; /* Ray statistics */
-
- /**********************************************************************/
- /* Start ray intersection: Clear statistics */
- /**********************************************************************/
- void StartIntersect()
- {
- RayStats.currentRayID = 1;
- RayStats.numRays = RayStats.intRay = RayStats.intRayID = 0;
- RayStats.intCone = RayStats.intCube = RayStats.intSphere = 0;
- RayStats.intPoly = 0;
- RayStats.rayCone = RayStats.rayCube = RayStats.raySphere = 0;
- RayStats.rayMesh = RayStats.rayPoly = 0;
- RayStats.rayBox = RayStats.intBox = 0;
- }
-
- /**********************************************************************/
- /* Print stats after intersection pass */
- /**********************************************************************/
- void EndIntersect(fptr)
- FILE *fptr;
- {
- FILE *fp;
-
- if (Option.statistics && RayStats.numRays != 0) {
- if (Option.device == PRINT)
- fp = stdout;
- else fp = fptr;
-
- fprintf(fp,"\n\tRay Tracing Statistics\n");
- fprintf(fp,"\t----------------------\n");
- fprintf(fp,"\tTotal number of rays shot = %ld\n", RayStats.numRays);
- fprintf(fp,"\tAverage number of intersections per ray = %g\n",
- (double)RayStats.intRay/(double)RayStats.numRays);
- if (Option.grid)
- fprintf(fp,"\tAverage number of intersections per ray (BV) = %g\n",
- (float) RayStats.intBox / (float)RayStats.numRays);
-
- fprintf(fp,"\tAverage number of intersections per ray with:\n");
- fprintf(fp,"\tCube=%g; Cone=%g; Cyl=%g; Sph=%g; Mesh=%g; Poly=%g\n",
- (float) RayStats.intCube / (float)RayStats.numRays,
- (float) RayStats.intCone / (float)RayStats.numRays,
- (float) RayStats.intCylinder / (float)RayStats.numRays,
- (float) RayStats.intSphere / (float)RayStats.numRays,
- (float) RayStats.rayMesh / (float)RayStats.numRays,
- (float) RayStats.intPoly / (float)RayStats.numRays);
-
- fprintf(fp,"\tAverage number of ray tests per ray with:\n");
- fprintf(fp,
- "\tBV=%g; Cube=%g; Cone=%g; Cyl=%g; Sph=%g; Mesh=%g; Poly=%g\n",
- (float) RayStats.rayBox / (float)RayStats.numRays,
- (float) RayStats.rayCube / (float)RayStats.numRays,
- (float) RayStats.rayCone / (float)RayStats.numRays,
- (float) RayStats.rayCylinder / (float)RayStats.numRays,
- (float) RayStats.raySphere / (float)RayStats.numRays,
- (float) RayStats.rayMesh / (float)RayStats.numRays,
- (float) RayStats.rayPoly / (float)RayStats.numRays);
-
- fprintf(fp,"\tAverage number of intersections per ray test with:\n");
- fprintf(fp,
- "\tBV=%g; Cube=%g; Cone=%g; Cyl=%g; Sph=%g; Mesh=%g; Poly=%g\n",
- (float) RayStats.intBox / ((float) RayStats.rayBox > 0.0 ?
- RayStats.rayBox : 1.0),
- (float) RayStats.intCube / ((float) RayStats.rayCube > 0.0 ?
- RayStats.rayCube : 1.0),
- (float) RayStats.intCone / ((float) RayStats.rayCone > 0.0 ?
- RayStats.rayCone : 1.0),
- (float) RayStats.intCylinder /
- ((float) RayStats.rayCylinder > 0.0 ? RayStats.rayCylinder : 1.0),
- (float) RayStats.intSphere / ((float) RayStats.raySphere > 0.0 ?
- RayStats.raySphere : 1.0),
- (float) RayStats.rayMesh,
- (float) RayStats.intPoly / ((float) RayStats.rayPoly > 0.0 ?
- RayStats.rayPoly : 1.0));
- fprintf (fp,"\n");
-
- if (Option.tablelog) {
- fp = rlogfile;
-
- fprintf(fp,"%ld \\\\\n", RayStats.numRays);
- fprintf(fp,"%g \\\\\n",
- (double)RayStats.intRay/(double)RayStats.numRays);
- if (Option.grid)
- fprintf(fp,"%g \\\\\n",
- (float) RayStats.intBox / (float)RayStats.numRays);
- fprintf(fp,"%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n",
- (float) RayStats.intCube / (float)RayStats.numRays,
- (float) RayStats.intCone / (float)RayStats.numRays,
- (float) RayStats.intCylinder / (float)RayStats.numRays,
- (float) RayStats.intSphere / (float)RayStats.numRays,
- (float) RayStats.rayMesh / (float)RayStats.numRays,
- (float) RayStats.intPoly / (float)RayStats.numRays);
-
- fprintf(fp,"%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n",
- (float) RayStats.rayBox / (float)RayStats.numRays,
- (float) RayStats.rayCube / (float)RayStats.numRays,
- (float) RayStats.rayCone / (float)RayStats.numRays,
- (float) RayStats.rayCylinder / (float)RayStats.numRays,
- (float) RayStats.raySphere / (float)RayStats.numRays,
- (float) RayStats.rayMesh / (float)RayStats.numRays,
- (float) RayStats.rayPoly / (float)RayStats.numRays);
-
- fprintf(fp,"%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n%g \\\\\n",
- (float) RayStats.intBox / ((float) RayStats.rayBox > 0.0 ?
- RayStats.rayBox : 1.0),
- (float) RayStats.intCube / ((float) RayStats.rayCube > 0.0 ?
- RayStats.rayCube : 1.0),
- (float) RayStats.intCone / ((float) RayStats.rayCone > 0.0 ?
- RayStats.rayCone : 1.0),
- (float) RayStats.intCylinder /
- ((float) RayStats.rayCylinder >0.0 ? RayStats.rayCylinder : 1.0),
- (float) RayStats.intSphere / ((float) RayStats.raySphere > 0.0 ?
- RayStats.raySphere : 1.0),
- (float) RayStats.rayMesh,
- (float) RayStats.intPoly / ((float) RayStats.rayPoly > 0.0 ?
- RayStats.rayPoly : 1.0));
- }
- }
-
- tstats.avg_ray /= (float) RayStats.numRays;
- }
-
- /**********************************************************************/
- /* Returns 0=cannot see object in direction raydir within given */
- /* distance or 1=can see object in ray direction raydir within given */
- /* distance (for form-factor visibility testing) */
- /**********************************************************************/
- int HitObject(point, raydir, distance)
- Vector point, raydir;
- double distance;
- {
- HitData hit;
- Ray ray;
-
- if (Option.debug) printf("\t> Testing visibility\n");
- Option.rayTransform = TRUE;
- Option.visibility = FORM_FACTOR;
- Option.shadow = TRUE;
- ray.origin = point;
- ray.dir = raydir;
- ray.shadow = TRUE; /* Doing visibility testing */
- ray.generation = -1; /* 1st generation */
- ray.visible= 1.0; /* Ray can still see destination */
- hit = RayIntersect(ray, distance); /* Find if any intersection */
-
- if (hit.obj == NULL || hit.distance > distance) {
- if (Option.debug)
- printf("\tObject missed everything!\n\n");
- return(FALSE); /* Missed everything or too far away */
- } else {
- if (Option.debug) {
- printf("\tHit %s%d [ray vis = %g, dist = %g]\n",
- hit.obj->name, hit.obj->id,
- ray.visible, hit.distance);
- if (hit.poly != 0)
- printf("\tPoly %s%d\n", hit.poly->name, hit.poly->id);
- }
- return(TRUE); /* Hit something along the way close enough */
- }
- }
-
- /**********************************************************************/
- /* Check if ray hits any object */
- /**********************************************************************/
- void RayObject(ray, hit, optr)
- Ray *ray;
- HitData *hit;
- register Objectt *optr;
- {
- switch(optr->primid) {
- case CONE:
- RayCone(ray, hit, optr); /* Test against cone */
- break;
- case CUBE:
- RayCube(ray, hit, optr); /* Test against cube */
- break;
- case CYLINDER:
- RayCylinder(ray, hit, optr); /* Test against cylinder */
- break;
- case MESH:
- RayMesh(ray, hit, optr); /* Test against polygonal mesh */
- break;
- case SPHERE:
- RaySphere(ray, hit, optr); /* Test against sphere */
- break;
- default:
- fprintf(stderr,"Invalid primitive type to intersect: %d\n", optr->primid);
- exit(1);
- break;
- }
- }
-
- /**********************************************************************/
- /* Find out what a ray intersects, return hit data (if any). */
- /* The ray is only allowed to travel up to max_distance distance from */
- /* the ray origin, if doing form-factor calculatiions. */
- /**********************************************************************/
- HitData RayIntersect(ray, max_distance)
- Ray ray;
- double max_distance;
- {
- int i;
- Object_List *olptr;
- Objectt *optr;
- HitData hit;
- Ray newRay;
- HBBox *hbox;
- double box_hit_dist;
- float ray_start, ray_end; /* Ray start and end times */
-
- ray.rayID = RayStats.currentRayID++;
- RayStats.numRays++;
- Reset_Hit(&hit,max_distance); /* Reset hit info */
-
- if (Option.debug) {
- printf("\tShooting Ray [id=%ld]: (%g,%g,%g) -> (%g,%g,%g), mdist=%g\n",
- ray.rayID,
- ray.origin.x, ray.origin.y, ray.origin.z, ray.dir.x,
- ray.dir.y, ray.dir.z, max_distance);
- fflush(stdout);
- }
-
- /* Start time */
- ray_start = Cpu_Time(&tstats.utime, &tstats.stime);
-
- if (Option.grid) { /* Use hierarchical BV tree */
-
- /* Test volumes in candidate list for current shaft */
- if (FF_Options.shaft_cull) {
- i=0; olptr=objlist;
- while (i<objlist_size && ray.visible>0.0) {
- hbox = olptr->hbox;
- if (hbox->poly == NULL)
- RayBVH(&ray, max_distance, hbox, &hit);
- else if ((hbox->poly != shootPatch) && (hbox->poly != recPatch))
- RayPolyBVH(&ray, max_distance, hbox, &hit);
- i++;
- olptr = olptr->next;
- }
- }
-
- /* Test volumes of objects in front of current receiver */
- else if (FF_Options.src_rec_cull) {
- i=0; olptr=objlist;
- while (i<objlist_size && ray.visible >0.0) {
- hbox = olptr->hbox;
- /* Only check if object is in front of source and receiver patches */
- if (olptr->is_obstructor) {
-
- /* Test if hit the box around object first. If so,
- then check the BV tree underneath */
- /* newRay = ray;
- RayStats.rayBox++;
- if (RayBoundingBox(*hbox->box, newRay, &box_hit_dist))
- if (box_hit_dist < hit.distance) {
- RayStats.intBox++;
- RayStats.intRay++;
- RayStats.intRayID++;
- */
-
- /* Check for intersection */
- RayBVH(&ray, max_distance, hbox, &hit);
- }
- i++;
- olptr = olptr->next;
- }
- }
-
- /* Traverse through all volumes in whole tree */
- else
- RayBVH(&ray, max_distance, &Scene_BVH, &hit);
-
- } else { /* Don't use hierarchical BV */
- optr = RadScene.objects; i=0;
-
- /* Check all objects in the scene until no more object, or
- hit an object closer than maximum distance */
- while((i<RadScene.num_objects) && (ray.visible>0.0)) {
- newRay = ray; /* Test new ray */
-
- /* Transform ray from world to model space first before intersect.
- Note. Do not tranform ray for polygonal meshes. */
- if ((Option.rayTransform) && (optr->primid != MESH))
- RayTransform(&ray, &newRay, *optr->WToM);
- RayObject(&newRay, &hit, optr);
- ray.visible = newRay.visible;
-
- /* Stop if hit object closer than maximum distance ray can travel
- for form factors. Otherwise continue checking. If two objects
- touch at the intersection point assume destination is still
- visible, and contine checking rest of objects */
- if (Option.visibility == FORM_FACTOR) {
- if (hit.distance < max_distance) { /* Destination is not visible */
- RayStats.intRay++;
- ray.visible = 0.0;
- }
- }
- optr = optr++; i++;
- }
- }
-
- /* Hit was too close */
- if (hit.obj != NULL && hit.distance < MIN_DISTANCE)
- hit.obj = NULL;
-
- ray_end = Cpu_Time(&tstats.utime, &tstats.stime);
- tstats.avg_ray += (ray_end - ray_start);
- return(hit);
- }
-
-
- /**********************************************************************/
- /* Ray Polygon-BVH traversal */
- /**********************************************************************/
- void RayPolyBVH(ray, max_distance, BVtree, hit)
- Ray *ray;
- double max_distance;
- HBBox *BVtree;
- HitData *hit; /* hit info */
- {
- int i;
- double box_hit_dist;
- Ray newRay; /* Ray to test */
- Objectt *object;
- Polygon *poly;
- HitData polyhit;
-
- if (Option.debug) {
- printf("\t\tRayPoly-BVH: visible=%g\n", ray->visible);
- printf("\tBox: %g,%g,%g -> %g,%g,%g\n",
- BVtree->box->min.x, BVtree->box->min.y, BVtree->box->min.z,
- BVtree->box->max.x, BVtree->box->max.y, BVtree->box->max.z);
- }
-
- if (ray->visible > 0.0) { /* Ray can still "see" destination */
-
- /* Check for intersection with polygon in tree */
- if (IsLeafBox(BVtree)) {
-
- /* Don't check source or receiver polygons. Can't hit themselves */
- if ((BVtree->poly == shootPatch) || (BVtree->poly == recPatch))
- return;
-
- newRay = *ray;
- object = BVtree->object; poly = BVtree->poly;
- if (Option.debug)
- printf("\tCheck Obj/Poly: %s%d / %s%d\n",
- object->name, object->id, poly->name, poly->id);
-
- /* Check if hits box around poly, then if hits polygon */
- polyhit = *hit;
- RayStats.rayPoly++;
- if (RayPolygon(poly, &newRay, &polyhit, max_distance,
- *BVtree->box, FF_Options.quadtri_ray)) {
- if (polyhit.distance < max_distance) {
- RayStats.intRay++;
- RayStats.intPoly++;
- ray->visible = 0.0;
- Store_HitInter(hit,polyhit.obj, polyhit.distance,
- polyhit.intersect.x, polyhit.intersect.y,
- polyhit.intersect.z);
- }
- }
-
- /* Test if hit bounding volume, if so continue down tree */
- } else {
- RayStats.rayBox++;
-
- /* Don't keep track of where it hits, just if it hits */
- newRay = *ray;
- if (RayBoundingBox(*BVtree->box, newRay, &box_hit_dist)) {
- if (box_hit_dist < hit->distance) {
- RayStats.intBox++;
- RayStats.intRay++;
- /* RayStats.intRayID++; */
- i=0;
- while(i<BVtree->num_children && ray->visible > 0.0) {
- RayPolyBVH(ray, max_distance, BVtree->child[i], hit);
- i++;
- }
- }
- }
- }
-
- }
- }
-
- /**********************************************************************/
- /* Ray-Object-BVH traversal */
- /* If find that object is hit and intersection distance is less that */
- /* maximum distance "max_distance" then stop */
- /**********************************************************************/
- void RayBVH(ray, max_distance, BVtree, hit)
- Ray *ray;
- double max_distance;
- HBBox *BVtree;
- HitData *hit; /* hit info */
- {
- int i;
- double box_hit_dist;
- Ray newRay; /* Ray to test */
- Objectt *object;
-
- if (Option.debug) {
- printf("\t\tRay-BVH: visible=%g\n", ray->visible);
- printf("\tBox: %g,%g,%g -> %g,%g,%g\n",
- BVtree->box->min.x, BVtree->box->min.y, BVtree->box->min.z,
- BVtree->box->max.x, BVtree->box->max.y, BVtree->box->max.z);
- }
-
- if (ray->visible > 0.0) { /* Ray can still "see" destination */
- /* Reset_Hit(hit,max_distance); */ /* Set hit info */
-
- /* Check for intersection with object in tree */
- if (BVtree->object != 0 && BVtree->poly == 0) {
- newRay = *ray;
- object = BVtree->object;
- if (Option.debug)
- printf("\tChecking object: %s%d\n", object->name, object->id);
- if ((Option.rayTransform) && (object->primid != MESH))
- RayTransform(ray, &newRay, *object->WToM);
-
- /* Test mesh using BV, just to direct compare for other primitives */
- if (object->primid != MESH)
- RayObject(&newRay, hit, object);
- else {
- /* Use polygon BVH or traverse mesh of polygons for intersect */
- if (Option.poly_grid)
- RayPolyBVH(ray, max_distance, BVtree, hit);
- else {
- RayStats.rayBox++;
- if (RayBoundingBox(*BVtree->box, newRay, &box_hit_dist)) {
- if (box_hit_dist < max_distance) {
- RayStats.intBox++;
- RayStats.intRay++;
- RayObject(&newRay, hit, object);
- }
- }
- }
- }
-
- /* Stop if hit an object closer than maximum distance
- ray can travel for form factors. */
- if (Option.visibility == FORM_FACTOR) {
- if (hit->distance < max_distance) {
- RayStats.intRay++;
- ray->visible = 0.0;
- }
- }
-
- /* Test if hit bounding volume, if so continue down tree */
- /* Note: rays not transformed, since bounding boxes are in
- world space coords already */
- } else if (BVtree->poly == 0 && BVtree->object == 0) {
- /* Don't keep track of where it hits, just if it hits ! */
- newRay = *ray;
- RayStats.rayBox++;
- if (RayBoundingBox(*BVtree->box, newRay, &box_hit_dist)) {
- if (box_hit_dist < hit->distance) {
- RayStats.intBox++;
- RayStats.intRay++;
- /* RayStats.intRayID++; */
- i=0;
- while(i<BVtree->num_children && ray->visible > 0.0) {
- RayBVH(ray, max_distance, BVtree->child[i], hit);
- i++;
- }
- }
- }
- }
-
- }
- }
-
-